#include "mhdf.h"
#include "util.h"
#include "status.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <H5Tpublic.h>
#include <H5Dpublic.h>
#include <H5Ppublic.h>

static struct mhdf_FileDesc* alloc_file_desc( mhdf_Status* status );
static void* realloc_data( struct mhdf_FileDesc** data, size_t append_bytes, mhdf_Status* status, int alignment );
static char buffer[512];

static struct mhdf_FileDesc* alloc_file_desc( mhdf_Status* status )
{
    struct mhdf_FileDesc* result;
    /* allocate a little short of a page */
    result = (struct mhdf_FileDesc*)mhdf_malloc( 4000, status );
    if( mhdf_isError( status ) ) return 0;

    memset( result, 0, sizeof( struct mhdf_FileDesc ) );
    result->total_size = 4000;
    result->offset     = ( (unsigned char*)result ) + sizeof( struct mhdf_FileDesc );
    return result;
}

static void* realloc_data( struct mhdf_FileDesc** data, size_t append_bytes, mhdf_Status* status, int alignment )
{
    void* result_ptr;
    struct mhdf_FileDesc* const input_ptr = *data;
    unsigned char* mem_ptr                = (unsigned char*)input_ptr;

    size_t new_size, occupied_size = input_ptr->offset - mem_ptr;

    size_t append_bytes_padded = append_bytes + alignment - 1;
    /* if the end of the allocated space is before the end of the required space */
    if( mem_ptr + input_ptr->total_size < input_ptr->offset + append_bytes_padded )
    {
        if( append_bytes_padded < input_ptr->total_size )
            new_size = 2 * input_ptr->total_size;
        else
            new_size = input_ptr->total_size + append_bytes_padded;
        *data = (struct mhdf_FileDesc*)mhdf_realloc( *data, new_size, status );
        if( mhdf_isError( status ) ) return 0;

        /* if realloc moved us to a different location in memory,
         * we need to update all of the internal pointers to
         * new locations relative to the start of the struct */
        if( *data != input_ptr )
        {
            mhdf_fixFileDesc( *data, input_ptr );
            mem_ptr           = (unsigned char*)( *data );
            ( *data )->offset = mem_ptr + occupied_size;
        }
        ( *data )->total_size = new_size;
    }

    result_ptr = ( *data )->offset;
    /* need to make this return pointer aligned */
    uintptr_t addr = (uintptr_t)( ( *data )->offset );
    int pad        = addr % alignment;
    if( pad > 0 )
    {
        ( *data )->offset += ( alignment - pad );
        result_ptr = ( *data )->offset;
    }
    /*printf("new address %p \n", result_ptr);*/
    ( *data )->offset += append_bytes;
    return result_ptr;
}

#define FIX_OFFSET( TYPE, FIELD ) \
    if( copy_ptr->FIELD != NULL ) \
    copy_ptr->FIELD = (TYPE)( ( (char*)( copy_ptr->FIELD ) - (char*)orig_addr ) + (char*)copy_ptr )

void mhdf_fixFileDesc( struct mhdf_FileDesc* copy_ptr, const struct mhdf_FileDesc* orig_addr )
{
    int i;

    API_BEGIN;
    FIX_OFFSET( int*, nodes.dense_tag_indices );
    FIX_OFFSET( int*, sets.dense_tag_indices );
    FIX_OFFSET( struct mhdf_ElemDesc*, elems );
    FIX_OFFSET( struct mhdf_TagDesc*, tags );

    FIX_OFFSET( int*, numEntSets );
    FIX_OFFSET( int**, defTagsEntSets );
    FIX_OFFSET( int**, defTagsVals );

    for( i = 0; i < 5; i++ )
    {
        if( copy_ptr->defTagsEntSets ) FIX_OFFSET( int*, defTagsEntSets[i] );
        if( copy_ptr->defTagsVals ) FIX_OFFSET( int*, defTagsVals[i] );
    }

    if( copy_ptr->elems != NULL )
    {
        for( i = 0; i < copy_ptr->num_elem_desc; ++i )
        {
            FIX_OFFSET( const char*, elems[i].handle );
            FIX_OFFSET( const char*, elems[i].type );
            FIX_OFFSET( int*, elems[i].desc.dense_tag_indices );
        }
    }

    if( copy_ptr->tags != NULL )
    {
        for( i = 0; i < copy_ptr->num_tag_desc; ++i )
        {
            FIX_OFFSET( const char*, tags[i].name );
            FIX_OFFSET( void*, tags[i].default_value );
            FIX_OFFSET( void*, tags[i].global_value );
            FIX_OFFSET( int*, tags[i].dense_elem_indices );
        }
    }
    API_END;
}

static struct mhdf_FileDesc* get_elem_desc( mhdf_FileHandle file_handle,
                                            struct mhdf_FileDesc* result,
                                            const char* elem_handle,
                                            int idx,
                                            mhdf_Status* status )
{
    hid_t id_pair[2];
    int poly;
    void* ptr;
    long junk;

    ptr = realloc_data( &result, strlen( elem_handle ) + 1, status, sizeof( char ) );
    if( !ptr ) return NULL;
    strcpy( ptr, elem_handle );
    result->elems[idx].handle = ptr;

    mhdf_getElemTypeName( file_handle, elem_handle, buffer, sizeof( buffer ), status );
    if( mhdf_isError( status ) )
    {
        free( result );
        return NULL;
    }

    ptr = realloc_data( &result, strlen( buffer ) + 1, status, sizeof( char ) );
    if( !ptr ) return NULL;
    strcpy( ptr, buffer );
    result->elems[idx].type = ptr;

    poly = mhdf_isPolyElement( file_handle, elem_handle, status );
    if( mhdf_isError( status ) )
    {
        free( result );
        return NULL;
    }

    if( !poly )
    {
        id_pair[0] = mhdf_openConnectivity( file_handle, elem_handle, &result->elems[idx].desc.vals_per_ent,
                                            &result->elems[idx].desc.count, &result->elems[idx].desc.start_id, status );
        if( id_pair[0] < 0 )
        {
            free( result );
            return NULL;
        }
        mhdf_closeData( file_handle, id_pair[0], status );
    }
    else
    {
        result->elems[idx].desc.vals_per_ent = -1;
        mhdf_openPolyConnectivity( file_handle, elem_handle, &result->elems[idx].desc.count, &junk,
                                   &result->elems[idx].desc.start_id, id_pair, status );
        if( id_pair[0] < 0 )
        {
            free( result );
            return NULL;
        }
        mhdf_closeData( file_handle, id_pair[0], status );
        mhdf_closeData( file_handle, id_pair[1], status );
    }

    result->elems[idx].desc.dense_tag_indices = NULL;
    result->elems[idx].desc.num_dense_tags    = 0;
    result->elems[idx].have_adj               = mhdf_haveAdjacency( file_handle, result->elems[idx].handle, status );
    if( mhdf_isError( status ) )
    {
        free( result );
        return 0;
    }

    return result;
}

static unsigned get_file_id_size( hid_t file_id_type, mhdf_Status* status )
{
    if( H5Tget_class( file_id_type ) != H5T_INTEGER )
    {
        mhdf_setFail( status, "Invalid handle or type class for file ID type." );
        return 0;
    }

    return H5Tget_size( file_id_type );
}

static struct mhdf_FileDesc* get_tag_desc( mhdf_FileHandle file_handle,
                                           struct mhdf_FileDesc* result,
                                           const char* name,
                                           int idx,
                                           hid_t type,
                                           mhdf_Status* status )
{
    void* ptr;
    int have_default, have_global;
    int valsize, size, close_type = 0;
    hsize_t array_len;

    ptr = realloc_data( &result, strlen( name ) + 1, status, sizeof( char ) );
    if( NULL == ptr ) return NULL;
    strcpy( ptr, name );
    result->tags[idx].name = ptr;

    mhdf_getTagInfo( file_handle, name, &result->tags[idx].type, &result->tags[idx].size, &result->tags[idx].storage,
                     &have_default, &have_global, &result->tags[idx].have_sparse, status );
    if( mhdf_isError( status ) )
    {
        free( result );
        return NULL;
    }

    /* For variable length tags, have_default and have_global will
       contain the size of the respective values.  For fixed-length
       tags, they are either zero or one.  Simplify later code by
       making them contain the size for both cases. */
    valsize = result->tags[idx].size;
    if( result->tags[idx].size >= 0 )
    {
        if( have_default ) have_default = valsize;
        if( have_global ) have_global = valsize;
    }

    result->tags[idx].default_value      = NULL;
    result->tags[idx].default_value_size = have_default;
    result->tags[idx].global_value       = NULL;
    result->tags[idx].global_value_size  = have_global;

    switch( result->tags[idx].type )
    {
        case mhdf_OPAQUE:
            type = 0;
            break;
        case mhdf_BOOLEAN:
            type = H5T_NATIVE_UCHAR;
            break;
        case mhdf_INTEGER:
            type = H5T_NATIVE_INT;
            have_default *= sizeof( int );
            have_global *= sizeof( int );
            valsize *= sizeof( int );
            break;
        case mhdf_FLOAT:
            type = H5T_NATIVE_DOUBLE;
            have_default *= sizeof( double );
            have_global *= sizeof( double );
            valsize *= sizeof( double );
            break;
        case mhdf_BITFIELD:
            have_default = ( have_default + 7 ) / 8;
            have_global  = ( have_global + 7 ) / 8;
            valsize      = ( valsize + 7 ) / 8;
            switch( valsize )
            {
                case 1:
                    type = H5Tcopy( H5T_NATIVE_B8 );
                    break;
                case 2:
                    type = H5Tcopy( H5T_NATIVE_B16 );
                    break;
                case 3:
                case 4:
                    valsize += 4 - valsize;  // to avoid fallthrough warning
                    type = H5Tcopy( H5T_NATIVE_B32 );
                    break;
                case 5:
                case 6:
                case 7:
                case 8:
                    valsize += 8 - valsize;  // to avoid fallthrough warning
                    type = H5Tcopy( H5T_NATIVE_B64 );
                    break;
                default:
                    free( result );
                    mhdf_setFail( status, "Cannot create a bit tag larger than 64-bits.  %d bits requested.\n",
                                  (int)valsize );
                    return NULL;
            }
            close_type = 1;
            break;
        case mhdf_ENTITY_ID:
            if( 0 == type ) type = H5T_NATIVE_ULONG;
            size = get_file_id_size( type, status );
            if( !size )
            {
                free( result );
                return NULL;
            }
            have_default *= size;
            have_global *= size;
            valsize *= size;
            break;
        default:
            mhdf_setFail( status, "Unknown mhdf_TagDataType value (%d) for tag (\"%s\")", (int)result->tags[idx].type,
                          name );
            free( result );
            return NULL;
    }
    result->tags[idx].bytes = valsize;

    if( result->tags[idx].type != mhdf_OPAQUE && result->tags[idx].type != mhdf_BITFIELD && result->tags[idx].size > 1 )
    {
        close_type = 1;
        array_len  = result->tags[idx].size;
#if defined( H5Tarray_create_vers ) && H5Tarray_create_vers > 1
        type = H5Tarray_create2( type, 1, &array_len );
#else
        type = H5Tarray_create( type, 1, &array_len, 0 );
#endif
        if( type < 0 )
        {
            mhdf_setFail( status, "H5Tarray_create failed for tag (\"%s\")", name );
            free( result );
            return NULL;
        }
    }

    if( have_default || have_global )
    {
        if( have_default )
        {
            ptr = realloc_data( &result, have_default, status, sizeof( int ) );
            if( NULL == ptr )
            {
                if( close_type )
                {
                    H5Tclose( type );
                }
                return NULL;
            }
            result->tags[idx].default_value = ptr;
        }
        if( have_global )
        {
            ptr = realloc_data( &result, have_global, status, sizeof( int ) );
            if( NULL == ptr )
            {
                if( close_type )
                {
                    H5Tclose( type );
                }
                return NULL;
            }
            result->tags[idx].global_value = ptr;
        }
        mhdf_getTagValues( file_handle, name, type, result->tags[idx].default_value, result->tags[idx].global_value,
                           status );
        if( close_type )
        {
            H5Tclose( type );
        }
        if( mhdf_isError( status ) )
        {
            free( result );
            return NULL;
        }
    }

    return result;
}

static void free_string_list( char** list, int count )
{
    int i;
    for( i = 0; i < count; ++i )
        free( list[i] );
    free( list );
}

struct mhdf_FileDesc* mhdf_getFileSummary( mhdf_FileHandle file_handle,
                                           hid_t file_id_type,
                                           mhdf_Status* status,
                                           int extraSetInfo )
{
    struct mhdf_FileDesc* result;
    hid_t table_id;
    int i, i1, numtags, j, k, size, *indices, have, num_tag_names = 0;
    unsigned int ui;
    void* ptr;
    char **elem_handles = 0, **tag_names = 0;
    unsigned char *array, *matrix;
    const char* pname[5] = { "PARALLEL_PARTITION", "MATERIAL_SET", "NEUMANN_SET", "DIRICHLET_SET", "GEOM_DIMENSION" };

    long* id_list;
    struct mhdf_TagDesc* tag_desc;
    long int nval, junk;
    hid_t table[3];
    hid_t data_type;

    API_BEGIN;

    mhdf_setOkay( status );
    result = alloc_file_desc( status );
    if( NULL == result ) return NULL;

    /* get node info */
    have = mhdf_haveNodes( file_handle, status );
    if( mhdf_isError( status ) )
    {
        free( result );
        return NULL;
    }
    if( have )
    {
        table_id = mhdf_openNodeCoords( file_handle, &result->nodes.count, &result->nodes.vals_per_ent,
                                        &result->nodes.start_id, status );
        if( table_id < 0 )
        {
            free( result );
            return NULL;
        }
        mhdf_closeData( file_handle, table_id, status );
    }
    else
    {
        result->nodes.count        = 0;
        result->nodes.vals_per_ent = 0;
        result->nodes.start_id     = 0;
    }

    /* get set info */
    result->sets.vals_per_ent = -1;
    have                      = mhdf_haveSets( file_handle, &result->have_set_contents, &result->have_set_children,
                                               &result->have_set_parents, status );
    if( mhdf_isError( status ) )
    {
        free( result );
        return NULL;
    }
    if( have )
    {
        table_id = mhdf_openSetMeta( file_handle, &result->sets.count, &result->sets.start_id, status );
        if( table_id < 0 )
        {
            free( result );
            return NULL;
        }
        mhdf_closeData( file_handle, table_id, status );
    }
    else
    {
        result->sets.count    = 0;
        result->sets.start_id = 0;
    }

    /* get element list */
    elem_handles = mhdf_getElemHandles( file_handle, &ui, status );
    if( elem_handles == NULL )
    {
        free( result );
        return NULL;
    }
    result->num_elem_desc = ui;

    /* allocate array of element descriptors */
    size = result->num_elem_desc * sizeof( struct mhdf_ElemDesc );
    ptr  = realloc_data( &result, size, status, sizeof( char* ) );
    if( NULL == ptr )
    {
        free( elem_handles );
        return NULL;
    }
    memset( ptr, 0, size );
    result->elems = ptr;

    /* Initialize each element descriptor */
    for( i = 0; i < result->num_elem_desc; ++i )
    {
        result = get_elem_desc( file_handle, result, elem_handles[i], i, status );
        if( NULL == result )
        {
            free( elem_handles );
            return NULL;
        }
    }

    /* get tag list */
    tag_names = mhdf_getTagNames( file_handle, &num_tag_names, status );
    if( mhdf_isError( status ) )
    {
        free( elem_handles );
        free( result );
        return NULL;
    }

    /* allocate array of tag descriptors */
    size = num_tag_names * sizeof( struct mhdf_TagDesc );
    ptr  = realloc_data( &result, size, status, sizeof( char* ) );
    if( NULL == ptr )
    {
        free( elem_handles );
        free_string_list( tag_names, result->num_tag_desc );
        return NULL;
    }
    memset( ptr, 0, size );
    result->tags         = ptr;
    result->num_tag_desc = num_tag_names;
    memset( result->tags, 0, size );

    /* Initialize each tag descriptor */
    for( i = 0; i < result->num_tag_desc; ++i )
    {
        result = get_tag_desc( file_handle, result, tag_names[i], i, file_id_type, status );
        if( NULL == result )
        {
            free( elem_handles );
            free_string_list( tag_names, num_tag_names );
            return NULL;
        }
    }

    /* Determine which dense tags are present */

    size  = ( 2 + result->num_elem_desc ) * result->num_tag_desc;
    array = mhdf_malloc( size, status );
    if( NULL == array )
    {
        free( elem_handles );
        free_string_list( tag_names, num_tag_names );
        free( result );
        return NULL;
    }
    memset( array, 0, size );
    matrix = array + ( 2 * result->num_tag_desc );

    for( j = 0; j < result->num_tag_desc; ++j )
    {
        if( mhdf_haveDenseTag( file_handle, tag_names[j], mhdf_node_type_handle(), status ) )
            matrix[-1 * result->num_tag_desc + j] = 1;
        if( mhdf_haveDenseTag( file_handle, tag_names[j], mhdf_set_type_handle(), status ) )
            matrix[-2 * result->num_tag_desc + j] = 1;
        for( i = 0; i < result->num_elem_desc; ++i )
            if( mhdf_haveDenseTag( file_handle, tag_names[j], elem_handles[i], status ) )
                matrix[i * result->num_tag_desc + j] = 1;
    }
    free( elem_handles );
    free_string_list( tag_names, result->num_tag_desc );

    /* Populate dense tag lists for element types */
    for( i = -2; i < result->num_elem_desc; ++i )
    {
        size = 0;
        for( j = 0; j < result->num_tag_desc; ++j )
            size += matrix[i * result->num_tag_desc + j];
        if( !size )
        {
            indices = NULL;
        }
        else
        {
            indices = realloc_data( &result, size * sizeof( int ), status, sizeof( int ) );
            if( NULL == indices )
            {
                free( array );
                return NULL;
            }

            k = 0;
            for( j = 0; j < result->num_tag_desc; ++j )
                if( matrix[i * result->num_tag_desc + j] ) indices[k++] = j;
            assert( k == size );
        }

        if( i == -2 )
        {
            result->sets.dense_tag_indices = indices;
            result->sets.num_dense_tags    = size;
        }
        else if( i == -1 )
        {
            result->nodes.dense_tag_indices = indices;
            result->nodes.num_dense_tags    = size;
        }
        else
        {
            result->elems[i].desc.dense_tag_indices = indices;
            result->elems[i].desc.num_dense_tags    = size;
        }
    }

    /* Populate dense tag lists for each tag */
    for( j = 0; j < result->num_tag_desc; ++j )
    {
        size = 0;
        for( i = -2; i < result->num_elem_desc; ++i )
            size += matrix[i * result->num_tag_desc + j];
        if( !size )
        {
            indices = 0;
        }
        else
        {
            indices = realloc_data( &result, size * sizeof( int ), status, sizeof( int ) );
            if( NULL == ptr )
            {
                free( array );
                return NULL;
            }

            k = 0;
            for( i = -2; i < result->num_elem_desc; ++i )
                if( matrix[i * result->num_tag_desc + j] ) indices[k++] = i;
            assert( k == size );
        }

        result->tags[j].num_dense_indices  = size;
        result->tags[j].dense_elem_indices = indices;
    }

    if( extraSetInfo )
    {
        /* open the table for parallel partitions, material sets, neumann sets,
         * dirichlet sets
         *  to determine number of parts, etc
         *   this is needed for iMOAB and VisIt plugin */
        const int NPRIMARY_SETS = 5;
        ptr                     = realloc_data( &result, NPRIMARY_SETS * sizeof( int ), status, sizeof( int ) );
        if( NULL == ptr || mhdf_isError( status ) )
        {
            free( array );
            return NULL;
        }
        result->numEntSets = ptr;
        for( i = 0; i < NPRIMARY_SETS; ++i )
            result->numEntSets[i] = 0;

        ptr = realloc_data( &result, NPRIMARY_SETS * sizeof( int* ), status, sizeof( int* ) );
        if( NULL == ptr || mhdf_isError( status ) )
        {
            free( array );
            return NULL;
        }
        result->defTagsEntSets = ptr;

        ptr = realloc_data( &result, NPRIMARY_SETS * sizeof( int* ), status, sizeof( int* ) );
        if( NULL == ptr || mhdf_isError( status ) )
        {
            free( array );
            return NULL;
        }
        result->defTagsVals = ptr;
        numtags             = result->num_tag_desc;

        for( i = 0; i < numtags; i++ )
        {
            tag_desc = &( result->tags[i] );
            for( k = 0; k < NPRIMARY_SETS; k++ ) /* number of default tags to consider */
            {
                if( strcmp( pname[k], tag_desc->name ) == 0 )
                {
                    if( tag_desc->have_sparse )
                    {
                        mhdf_openSparseTagData( file_handle, pname[k], &nval, &junk, table, status );
                        if( mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        /* for sparse tags, read */
                        result->numEntSets[k] = nval;
                        if( nval <= 0 ) continue; /* do not do anything */

                        ptr = realloc_data( &result, nval * sizeof( int ), status, sizeof( int ) );
                        if( NULL == ptr || mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        memset( ptr, 0, nval * sizeof( int ) );
                        result->defTagsEntSets[k] = ptr;
                        tag_desc                  = &( result->tags[i] );

                        ptr = realloc_data( &result, nval * sizeof( int ), status, sizeof( int ) );
                        if( NULL == ptr || mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        memset( ptr, 0, nval * sizeof( int ) );
                        result->defTagsVals[k] = ptr;
                        tag_desc               = &( result->tags[i] ); /* this is because the tag might point to
                                                              something else*/

                        /* make room for the long array type
                          is it long or something else? */
                        id_list = mhdf_malloc( nval * sizeof( long ), status );
                        /* fill the id with values, then convert to int type (-set start)

                         mhdf_read_data( table_id, offset, count, int_type, id_list, H5P_DEFAULT,
                         status );*/

                        data_type = H5Dget_type( table[0] );

                        mhdf_read_data( table[0], 0, nval, data_type, id_list, H5P_DEFAULT, status );
                        if( mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        H5Tclose( data_type );

                        for( i1 = 0; i1 < nval; i1++ )
                            result->defTagsEntSets[k][i1] = (int)( id_list[i1] - result->sets.start_id + 1 );
                        /* now read values, integer type */
                        data_type = H5Dget_type( table[1] );
                        mhdf_read_data( table[1], 0, nval, data_type, result->defTagsVals[k], H5P_DEFAULT, status );
                        if( mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        H5Tclose( data_type );
                        mhdf_closeData( file_handle, table[0], status );
                        if( mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        mhdf_closeData( file_handle, table[1], status );
                        if( mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        free( id_list );
                    }
                    else if( 0 == k || 1 == k )
                    { /* parallel partition or material sets should still work if dense
 could be dense tags on sets */
                        if( !mhdf_haveDenseTag( file_handle, pname[k], mhdf_set_type_handle(), status ) ) continue;
                        table[0] =
                            mhdf_openDenseTagData( file_handle, pname[k], mhdf_set_type_handle(), &nval, status );
                        if( mhdf_isError( status ) )
                        {
                            continue; /* do not error out if not a dense tag either */
                        }
                        result->numEntSets[k] = nval;
                        if( nval <= 0 ) continue; /* do not do anything */

                        /*
                         * if dense parallel partition or material set, we know what to expect
                         */
                        result->numEntSets[k] = nval; /* k could be 0 or 1 */
                        if( nval <= 0 ) continue;     /* do not do anything */

                        ptr = realloc_data( &result, nval * sizeof( int ), status, sizeof( int ) );
                        if( NULL == ptr || mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        memset( ptr, 0, nval * sizeof( int ) );
                        result->defTagsEntSets[k] = ptr;
                        tag_desc                  = &( result->tags[i] );

                        ptr = realloc_data( &result, nval * sizeof( int ), status, sizeof( int ) );
                        if( NULL == ptr || mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        memset( ptr, 0, nval * sizeof( int ) );
                        result->defTagsVals[k] = ptr;
                        tag_desc               = &( result->tags[i] ); /* this is because the tag might point to
                                                              something else*/

                        for( i1 = 0; i1 < nval; i1++ )
                        {
                            result->defTagsEntSets[k][i1] = i1 + 1;
                            /*result -> defTagsVals[k][i1] = i1; we know how the partition looks
                             * like  */
                        }
                        /* fill in the data with the dense tag values
                          because dense, sets will be in order

                          we know it has to be integer */
                        mhdf_readTagValues( table[0], 0, nval, H5T_NATIVE_INT, result->defTagsVals[k], status );
                        if( mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                        mhdf_closeData( file_handle, table[0], status );
                        if( mhdf_isError( status ) )
                        {
                            free( array );
                            return NULL;
                        }
                    }
                }
            }
        }
    }
    /* Compact memory and return */
    free( array );
    result->total_size = result->offset - (unsigned char*)result;

    API_END;
    return result;
}
